/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.transas.zorlog.data.log;

import com.transas.zorlog.data.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *
 * @author amalikov
 */
public class TextLogLoader implements LogLoader {

	public TextLogLoader(String logFileName, String cfgFileName) {
		this.logFileName = logFileName;
		this.cfgFileName = cfgFileName;
	}	
	
	@Override
	public DataSource read(ProgressInformer informer) throws FileNotFoundException, IOException {
		ds = new DataSourcePlain();
		readCfg();
		readLog(informer);
		return ds;
	}
	
	private void readCfg() throws FileNotFoundException, IOException {
		try (Reader file = new FileReader(cfgFileName)) {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new InputSource(file));
			readTimeConfig(doc.getDocumentElement());
        } catch (ParserConfigurationException | SAXException | IOException ex) {
			Logger.getLogger(Config.class.getName()).log(Level.SEVERE, null, ex);
		}
	}
	
	/**
	 * Parses timeline tag
	 */
	private void readTimeConfig(Node root) {
		Node node = ((Element)root).getElementsByTagName("timeline").item(0);
		NamedNodeMap attrs = node.getAttributes();
			
		Node valueNode = attrs.getNamedItem("value");
		if (valueNode != null)
			timeValue = valueNode.getNodeValue();
			
		Node scaleNode = attrs.getNamedItem("scale");
		if (scaleNode != null)
			timeScale = Double.parseDouble(scaleNode.getNodeValue());
			
		Node formatNode = attrs.getNamedItem("format");
		if (formatNode != null)
			timeFormat = formatNode.getNodeValue();

		Node playbackNode = attrs.getNamedItem("playback");
		if (playbackNode != null)
			playbackRate = Float.parseFloat(playbackNode.getNodeValue());
	}
	
	
	private void readLog(ProgressInformer informer) throws FileNotFoundException, IOException {
		try (InputStream file = new FileInputStream(logFileName)) {
			
			BufferedReader br = new BufferedReader(new InputStreamReader(file));
			
			String head = br.readLine();
			if (head == null)
				return;

			detectSplitter(head);
			String[] names = head.split(splitter);
			ds.create(names);
			
			final int total = file.available();

			while (true) {
				String line = br.readLine();
				if (line == null)
					break;
				
				if (!line.isEmpty()) {
					String[] strValues = line.split(splitter);
					double[] values = new double[names.length];
					for (int i = 0; i < values.length; ++i) {
						if (i < strValues.length) {
							try {
								values[i] = Double.parseDouble(strValues[i]);
							} catch (NumberFormatException ex) {
								values[i] = 0;
							}
						} else
							values[i] = 0;
					}
					ds.addRow(values);
				}
				
				informer.set((int)(100 * (1 - (float)file.available() / total) + 0.5));
			}
			
			setTimeSource();
		}		
	}
	
	private void detectSplitter(String str) {
		final String[] splitters = {"\\s+", ",", ";"};
		int max = -1;
		for (String s : splitters) {
			int n = str.split(s).length;
			if (n > max) {
				max = n;
				splitter = s;
			}
		}
	}
	
	private void setTimeSource() {
		TimeFormatter fmt = "hms".equals(timeFormat) ? new TimeFormatterHMS() : new TimeFormatterSimple();
		TimeSource ts = "".equals(timeValue) ? 
				new TimeSourceFromIndex(timeScale, fmt, playbackRate) : 
				new TimeSourceFromData(ds.getValues(timeValue), timeScale, fmt, playbackRate);
		ds.setTimeSource(ts);
	}
	
	private String logFileName;
	private String cfgFileName;
	private DataSourcePlain ds;
	private String splitter;
	private String timeValue = "";
	private double timeScale = 1;
	private	String timeFormat = "simple";	
	private float playbackRate = 0.05f;
}
